Skip to content

[2/5] Aitools: install writes state, interactive agent selection, idempotent install#4811

Merged
simonfaltum merged 8 commits intomainfrom
simonfaltum/aitools-pr2-install
Mar 25, 2026
Merged

[2/5] Aitools: install writes state, interactive agent selection, idempotent install#4811
simonfaltum merged 8 commits intomainfrom
simonfaltum/aitools-pr2-install

Conversation

@simonfaltum
Copy link
Copy Markdown
Member

@simonfaltum simonfaltum commented Mar 22, 2026

PR Stack

  1. [1/5] State + release discovery + directory rename ([1/5] Aitools: state tracking, manifest source, directory rename #4810)
  2. [2/5] Install writes state + interactive agent selection (this PR)
  3. [3/5] Update + uninstall + version commands ([3/5] Aitools: update, uninstall, and version commands #4812)
  4. [4/5] List improvements + command restructuring + flags ([4/5] Aitools: list command, flat structure, --skills/--agents/--include-experimental flags #4813)
  5. [5/5] Project scope (--project/--global) (pending)

Base: simonfaltum/aitools-pr1-state (PR 1)

Why

Install currently has no state tracking, no filtering, and outputs every file download to the console. Users can't tell what version they have, and there's no way to install for specific agents.

Changes

Before: skills install downloads everything, prints every file, has no state, no filtering, no agent selection.

Now:

  • InstallSkillsForAgents(ctx, src, agents, opts) as the core install function. InstallAllSkills becomes a thin wrapper (signature preserved for cmd/apps/init.go compat).
  • State written to .state.json after successful install. Merges with existing state (doesn't overwrite).
  • Idempotent: second install skips already-present skills with matching versions.
  • Experimental filtering: skip experimental: true skills by default.
  • min_cli_version enforcement: skip incompatible skills with warning (hard error for single-skill install).
  • Interactive agent selection via charmbracelet/huh multi-select. Skip prompt for 1 agent, all detected for non-interactive.
  • Legacy install detection: prints "reinstall" message when old install found without state.
  • Concise default output (2 lines). Per-file detail only at debug level.

Test plan

  • State created after install-all and install-single
  • Experimental filtering (skip by default, include with flag)
  • min_cli_version: warning for all, hard error for single
  • Idempotent: skip same version, update changed
  • Legacy detection with helpful message
  • Interactive prompt for 2+ agents, skip for 1
  • Non-interactive: all detected, no prompt
  • InstallAllSkills signature preserved
  • Concise output, per-file at debug level

@github-actions
Copy link
Copy Markdown

Suggested reviewers

Based on git history of the changed files, these people are best suited to review:

  • @arsenyinfo -- recent work in experimental/aitools/lib/installer/, experimental/aitools/cmd/

Confidence: high

Eligible reviewers

Based on CODEOWNERS, these people or teams could also review:

@databricks/eng-apps-devex, @lennartkats-db

Suggestions based on git history of 5 changed files (4 scored). See CODEOWNERS for path-specific ownership rules.

github-merge-queue bot pushed a commit that referenced this pull request Mar 25, 2026
## PR Stack

This is part of the aitools feature-complete initiative. PRs should be
reviewed and merged in order.

1. **[1/5] State + release discovery + directory rename** (this PR)
2. [2/5] Install writes state + interactive agent selection (#4811)
3. [3/5] Update + uninstall + version commands (#4812)
4. [4/5] List improvements + command restructuring + flags (#4813)
5. [5/5] Project scope (--project/--global) (pending)

Manifest v2 PR: (pending in databricks-agent-skills)

## Why

The aitools skills installer has no state tracking. There's no record of
what was installed, at what version, or when. This blocks every
lifecycle command (update, uninstall, version). The manifest fetching
logic is also hardcoded with no abstraction for testing.

## Changes

Before: Skills install to `~/.databricks/agent-skills/` with no state
file. `FetchManifest` is inlined in `installer.go` with a hardcoded ref
and no way to mock it in tests.

Now:
- `InstallState` type with `LoadState`/`SaveState` (atomic write via
temp+rename) for tracking installed skills, release ref, and timestamps
- `ManifestSource` interface with `GitHubManifestSource`, separating
manifest fetching from install logic. Enables test mocking.
- `FetchLatestRelease` to discover newest release from GitHub API. Falls
back to pinned ref on network failure.
- v2 fields on `SkillMeta` (`Experimental`, `Description`, `MinCLIVer`)
with omitempty for backward compat with v1 manifests
- Canonical directory renamed from `.databricks/agent-skills` to
`.databricks/aitools/skills`
- Backward-compat check in `HasDatabricksSkillsInstalled` for the old
path

No behavior changes to existing commands except the directory path.

## Test plan

- [x] `LoadState` returns nil, nil for nonexistent file
- [x] `SaveState` + `LoadState` roundtrip preserves all fields including
optional ones
- [x] `SaveState` creates nested directories, writes trailing newline
- [x] `LoadState` returns error for corrupt JSON
- [x] `GlobalSkillsDir` resolves correctly
- [x] `ProjectSkillsDir` returns ErrNotImplemented
- [x] `HasDatabricksSkillsInstalled` detects legacy path
- [x] All existing aitools tests still pass

---------

Co-authored-by: Arseny Kravchenko <arsenyinfo@users.noreply.github.com>
Base automatically changed from simonfaltum/aitools-pr1-state to main March 25, 2026 22:10
@simonfaltum simonfaltum force-pushed the simonfaltum/aitools-pr2-install branch from fde04db to 3cee3a7 Compare March 25, 2026 22:18
…nstall

Introduces the core InstallSkillsForAgents function that handles:
- Fetching manifest via ManifestSource interface
- Filtering experimental skills and enforcing min_cli_version
- Idempotent install (skips already-installed skills at same version)
- Legacy install detection (skills on disk without state file)
- State persistence after successful install
- Concise output (two lines: installing header + summary)

Adds interactive agent selection in cmd/skills.go using huh multi-select
when multiple agents are detected in an interactive terminal.

Preserves InstallAllSkills signature (func(context.Context) error) for
the cmd/apps/init.go callback.

Co-authored-by: Isaac
… assertion

- Fix --experimental -> --include-experimental in error message
- Merge new skills into existing state instead of overwriting
- Move FetchManifest log from Info to Debug for concise output
- Handle singular/plural in Installed N skill(s) message
- Assert min_cli_version skip warning appears in test output

Co-authored-by: Isaac
…gacy guard, local copy

- Make idempotency check agent-aware: verify every requested agent has the
  skill on disk before skipping, so adding a new agent triggers reinstall.
- Add --experimental flag to skills install and top-level install commands
  (previously referenced in error message but missing from CLI).
- Block targeted install (install <skill>) on legacy setups without state
  to prevent writing incomplete state that hides the legacy warning.
- Remove redundant state reload: use single LoadState + in-place mutation.
- Copy files locally from canonical dir instead of re-downloading for
  single-agent and symlink-fallback paths.
- Add IncludeExperimental semantics comment on state field.
- Fix misleading test comment and add NotContains assertion for unchanged skill.

Co-authored-by: Isaac
@simonfaltum simonfaltum force-pushed the simonfaltum/aitools-pr2-install branch from 3cee3a7 to 5f87b4a Compare March 25, 2026 22:45
@simonfaltum simonfaltum enabled auto-merge March 25, 2026 22:46
@simonfaltum simonfaltum added this pull request to the merge queue Mar 25, 2026
Merged via the queue into main with commit 3fbef89 Mar 25, 2026
15 checks passed
@simonfaltum simonfaltum deleted the simonfaltum/aitools-pr2-install branch March 25, 2026 22:54
@eng-dev-ecosystem-bot
Copy link
Copy Markdown
Collaborator

Commit: 3fbef89

Run: 23568335822

github-merge-queue bot pushed a commit that referenced this pull request Mar 25, 2026
## PR Stack

1. [1/5] State + release discovery + directory rename (#4810)
2. [2/5] Install writes state + interactive agent selection (#4811)
3. **[3/5] Update + uninstall + version commands** (this PR)
4. [4/5] List improvements + command restructuring + flags (#4813)
5. [5/5] Project scope (--project/--global) (pending)

**Base**: `simonfaltum/aitools-pr2-install` (PR 2)

## Why

Users can install skills but can't update, uninstall, or check what
version they have. These are core lifecycle gaps.

## Changes

Three new commands, each small but grouped because they share patterns.

**`aitools update`**: Compares installed release against latest.
Downloads changed skills. Flags: `--check` (dry run), `--force`
(re-download), `--no-new` (don't auto-add new manifest skills).
Authoritative release detection (distinguishes real API response from
fallback). Applies experimental and min_cli_version filtering. Warns on
skills removed from manifest.

**`aitools uninstall`**: Removes skill directories from canonical
location. Removes symlinks from ALL agent directories (full registry
scan, not just detected). Cleans orphaned symlinks. Only removes
symlinks pointing to canonical dir (safe for third-party skills).
Deletes `.state.json` on success.

**`aitools version`**: Shows installed version, skill count, last
updated date. Best-effort staleness check against latest release.
Graceful offline degradation. Suppresses staleness check when
`DATABRICKS_SKILLS_REF` is set.

## Test plan

- [x] Update: no state -> error, already up to date, version diff, check
dry run, force, no-new, new skill auto-installed, removed skill warning
- [x] Uninstall: removes dirs + symlinks, orphan cleanup, state
deletion, no state -> error, missing dirs handled
- [x] Version: installed/up-to-date, update available, not installed,
offline graceful
- [x] All lint checks pass
github-merge-queue bot pushed a commit that referenced this pull request Mar 26, 2026
…ude-experimental flags (#4813)

## PR Stack

1. [1/5] State + release discovery + directory rename (#4810)
2. [2/5] Install writes state + interactive agent selection (#4811)
3. [3/5] Update + uninstall + version commands (#4812)
4. **[4/5] List improvements + command restructuring + flags** (this PR)
5. [5/5] Project scope (--project/--global) (#4814)

Manifest v2 PR: databricks/databricks-agent-skills#35

**Base**: `simonfaltum/aitools-pr3-lifecycle` (PR 3)

## Why

Commands are nested under `skills` which burns namespace for future
component types (hooks, etc.). There's no way to install specific
skills, target specific agents from the CLI, or see installed status in
the list output.

## Changes

**New `list` command**: Table output with skill names, versions,
installed status, `[experimental]` tags. Sorted alphabetically. Uses
`tabwriter` for alignment.

**Flat command structure**: `aitools
install/update/uninstall/list/version` at the top level. Hidden `skills
install` and `skills list` aliases for backward compat.

**Flags**:
- `--skills` (string, comma-separated) on install, update, uninstall:
operate on specific skills
- `--skills` (bool) on list, version: show detailed skills view
- `--agents` (string, comma-separated) on install: target specific
agents, validates against registry, skips interactive prompt
- `--include-experimental` on install: include experimental skills

**Selective uninstall**: `--skills` on uninstall removes only named
skills, preserves state file with remaining.

## Test plan

- [x] `install --skills`, `--agents`, `--include-experimental` flags
work
- [x] `--agents` validates against registry, errors on unknown
- [x] `uninstall --skills` selective removal, state preserved
- [x] `update --skills` selective update
- [x] `list` shows detailed table
- [x] `skills install` and `skills list` hidden aliases work (Execute
path tested)
- [x] `cmd/apps/init.go` integration preserved
- [x] All lint checks pass
github-merge-queue bot pushed a commit that referenced this pull request Mar 26, 2026
## PR Stack

1. [1/5] State + release discovery + directory rename (#4810)
2. [2/5] Install writes state + interactive agent selection (#4811)
3. [3/5] Update + uninstall + version commands (#4812)
4. [4/5] List improvements + command restructuring + flags (#4813)
5. **[5/5] Project scope (--project/--global)** (this PR)

Manifest v2 PR: databricks/databricks-agent-skills#35

**Base**: `simonfaltum/aitools-pr4-restructure` (PR 4)

## Why

Skills are currently global-only. Teams working on the same project
can't share a curated set of skills via their repo. Project-scoped
installation puts skills alongside the code, so they can be committed to
git and shared.

## Changes

Before: All skills install to `~/.databricks/aitools/skills/` (global
only).

Now:
- `--project` flag on install, update, uninstall: operates on
`<cwd>/.databricks/aitools/skills/`
- `--global` flag: explicit global scope (default behavior)
- `--global` + `--project` -> error
- Interactive scope prompt on install (default: global). Uses
`huh.NewSelect` in cmd layer.
- Non-interactive defaults to global.
- `SupportsProjectScope` field on `Agent` struct. Only Claude Code and
Cursor support project scope.
- Incompatible agents get a warning, not an error: "Skipped <agent>:
does not support project-scoped skills."
- Version shows both scopes when both exist.
- State includes `scope: "project"` field for project installs.

## Test plan

- [x] `--project` installs to cwd-relative directory
- [x] `--global` + `--project` -> error
- [x] No flag, interactive -> scope prompt shown, default is global
- [x] No flag, non-interactive -> global (no prompt)
- [x] Incompatible agents warned, not errored
- [x] Symlinks only created for capable agents in project scope
- [x] Version shows both scopes when both exist
- [x] `SupportsProjectScope` set correctly for all 6 agents
- [x] All lint checks pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants